package dao

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/wonderivan/logger"
	"time"
)

type Transaction struct {
	//主键，无实际含义
	Id int `xorm:"pk" json:"-"`
	//用户ID
	Uid int64 `xorm:"uid" json:"uid"`
	//交易平台
	AppId string `xorm:"appid" json:"app_id"`
	//交易订单号 本地订单
	OrderId int64 `xorm:"orderid" json:"order_id"`
	//交易类型 IN/OUT
	TradeType string `xorm:"trade_type" json:"trade_type"`
	//币种
	Currency string `xorm:"currency" json:"currency"`
	//支付金额
	Amount int `xorm:"amount" json:"amount"`
	//支付渠道
	TradeChannel string `xorm:"trade_channel" json:"trade_channel"`
	//交易号码
	TransactionNo string `xorm:"transaction_no" json:"transaction_no"`
	//交易流水号
	ChannelId string `xorm:"channel_id" json:"channel_id"`
	//设备ID
	DeviceId string `xorm:"device_id" json:"-"`
	//交易状态 'Success','Fail','InProgress','UnConfirmed','Unknown'
	Status string `xorm:"status" json:"status"`
	//信息版本号
	Version int `xorm:"version" json:"-"`
	//订单手动调整的操作人
	ModifiedBy string `xorm:"modifiedby" json:"-"`
	//备注
	Remark  string    `xorm:"remark" json:"-"`
	Created time.Time `xorm:"created" json:"-"`
	Updated time.Time `xorm:"updated" json:"-"`
}

func (t *Transaction) TableName() string {
	return "transaction"
}

func (d *Dao) NewOrder(order *Transaction) (err error) {
	_, err = d.client.Insert(order)
	return err
}

func (d *Dao) UpdateOrder(toUpdate *Transaction) (err error) {
	var (
		affect    int64
		orderInfo *Transaction
	)
	orderInfo, err = d.GetOrderById(orderInfo.OrderId)
	if err != nil {
		return
	}
	if orderInfo == nil {
		return fmt.Errorf("order not found")
	}
	if orderInfo.Status != "InProgress" {
		return fmt.Errorf("order completed")
	}
	toUpdate.Version += orderInfo.Version
	affect, err = d.client.Where("order_id = ? && version = ? ", toUpdate.OrderId, toUpdate.Version).Update(toUpdate)
	if err != nil {
		return
	}
	if affect != 0 {
		logger.Warn("affect must one record, but %d", affect)
	}
	return
}

func (d *Dao) GetOrderById(orderId int64) (trans *Transaction, err error) {
	var has bool
	trans = &Transaction{}
	has, err = d.client.Where("order_id = ?", orderId).Get(trans)
	if err != nil {
		return
	}
	if !has {
		err = fmt.Errorf("not found")
		return
	}
	return
}

func (d *Dao) FetchOrderByCond(cond interface{}) (trans []*Transaction, err error) {
	trans = make([]*Transaction, 0)
	err = d.client.Where(cond).Find(&trans)
	return
}

func (d *Dao) LockOrderStatus(orderId int64) (ok bool, err error)  {
	client := d.redisClient.Get()
	defer  client.Close()
	key := fmt.Sprintf("order:%d:status:lock", orderId)
	ok, err = redis.Bool(client.Do("SETNX", key))
	if err != nil || !ok{
		return
	}
	client.Do("EXPIRE", key, 10)
	return
}

func (d *Dao) ReleaseOrderStatus(orderId int64) (err error){
	client := d.redisClient.Get()
	defer  client.Close()
	key := fmt.Sprintf("order:%d:status:lock", orderId)
	_, err =client.Do("DEL", key)
	return
}